﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace DigitalQuran.Qnl
{
    public sealed class Scanner : IEnumerable<Token>
    {
        Dictionary<TokenType, Regex> Patterns;                

        public Scanner()
        {
            Patterns = new Dictionary<TokenType, Regex>
            {
                { TokenType.Number, CreateRegex(@"[0-9]+") },
                { TokenType.WhiteSpace, CreateRegex(@"\s+") },
                { TokenType.Identifier, CreateRegex(@"[A-Z|a-z]+") },                
                { TokenType.Comma, CreateRegex(@",") },
                { TokenType.Hyphen, CreateRegex(@"-") },
                { TokenType.Unknown, CreateRegex(@"[^!\s]+") },
            };
        }

        Regex CreateRegex(string pattern)
        {
            return new Regex(pattern, RegexOptions.Compiled);
        }

        public string Text { get; set; }
        
        public IEnumerator<Token> GetEnumerator()
        {
            int startPos = 0;
            Match match = null;

            Token token = null;
            TokenType foundToken = TokenType.None;
            int max = Text.Length;

            while (startPos < max)
            {
                do
                {
                    foreach (var pattern in Patterns)
                    {
                        match = pattern.Value.Match(Text, startPos);
                        if (match.Success && match.Index == startPos)
                        {
                            foundToken = pattern.Key;
                            startPos += match.Length;
                            break;
                        }
                    }

                } while (foundToken == TokenType.WhiteSpace && startPos < Text.Length);

                if (match != null && foundToken != TokenType.WhiteSpace)
                {
                    token = new Token()
                    {
                        Index = startPos - match.Length,
                        Length = match.Length,
                        Type = foundToken,
                        Text = match.Captures[0].Value
                    };

                    yield return token;
                }

            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

    public class Token
    {        
        public int Index { get; internal set; }        

        public int Length { get; internal set; }

        public string Text { get; internal set; }

        public TokenType Type { get; set; }
    }

    public enum TokenType
    {
        None,
        Unknown,
        Number,
        WhiteSpace,
        Identifier,
        Comma,
        Hyphen,
    }
}